﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;

namespace SpectationClient {
    public static class TextHelper {

        /// <summary>
        /// Function that return true if the String "text" can be parsed as a number of type "numbertype".
        /// </summary>
        /// <param name="numbertype">the datatype that should be used to parse the number</param>
        /// <param name="text">the string containing a textual representation of a number</param>
        /// <returns>return value: 
        /// == true if "text" is empty string (NULL or "")
        /// == true if "text" can be parsed as type "numbertype"
        /// == false if "text" is not empty and can not be parsed as type "numbertype"
        /// </returns>
        public static bool TryParsingNumber(Type numbertype, String text) { 
            bool has_text = text != null && text.Length > 0;
            Int16 i16;
            Int32 i32;
            Int64 i64;
            UInt16 ui16;
            UInt32 ui32;
            UInt64 ui64;
            Single f16;
            Double f64;
            Decimal dec;

            if(numbertype == typeof(Int16)) return has_text && Int16.TryParse(text, out i16);
            if (numbertype == typeof(Int32)) return has_text && Int32.TryParse(text, out i32);
            if (numbertype == typeof(Int64)) return has_text && Int64.TryParse(text, out i64);
            if (numbertype == typeof(Single)) return has_text && Single.TryParse(text, out f16);
            if (numbertype == typeof(Double)) return has_text && Double.TryParse(text, out f64);
            if (numbertype == typeof(UInt16)) return has_text && UInt16.TryParse(text, out ui16);
            if (numbertype == typeof(UInt32)) return has_text && UInt32.TryParse(text, out ui32);
            if (numbertype == typeof(UInt64)) return has_text && UInt64.TryParse(text, out ui64);
            if (numbertype == typeof(Decimal)) return has_text && Decimal.TryParse(text, out dec);
            throw new Exception("Class: TextHelper, Function: TryParsingNumber, Error: Type is not supported");
            
        }

        /// <summary>
        /// Parses IDs (positive integer values) from a text string. 
        /// Ranges as "13-15" will be interpreted as "13,14,15"
        /// </summary>
        /// <param name="text"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static Int64[] parseIDs(String text, String separator=",") {
            string[] parts = text.Trim().Split(new String[] { separator }, StringSplitOptions.RemoveEmptyEntries);
           
            SortedSet<Int64> results = new SortedSet<Int64>();
            Regex range = new Regex(@"\d+-\d+");
            Regex id = new Regex(@"\d+");
            foreach(String p in parts) {
                if(range.IsMatch(p)) {
                    MatchCollection mc = id.Matches(p);
                    if(mc.Count < 2) continue;
                    Int64 n1, n2;
                    if(Int64.TryParse(mc[0].Value, out n1) && Int64.TryParse(mc[1].Value, out n2)){
                        Int64 iStart = Math.Min(n1, n2);
                        Int64 iEnd = Math.Max(n1, n2);
                        for(Int64 i = iStart; i <= iEnd; i++) {
                            results.Add(i);
                        }
                    }


                } else { 
                    Int64 num;
                    if(Int64.TryParse(p, out num)) results.Add(num);
                }    
            
            
            }

            return results.ToArray() ;
        }

        /// <summary>
        /// Parses double values from a string which can be separated by a ',' or any other separator
        /// </summary>
        /// <param name="text"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static Double[] parseDoubles(String text, String separator=",") {
            string[] parts = text.Split(new String[] { separator }, StringSplitOptions.RemoveEmptyEntries);
            Double res;
            return (from p in parts
                    where Double.TryParse(p, out res)
                    select Double.Parse(p)).ToArray();
           
        }

        public static String combine<T>(HashSet<T> hashSet, String separator) {
            return TextHelper.combine(hashSet.ToArray<T>(), separator);
        }

        public static String combine(DataRow row, String separator) {
            return TextHelper.combine(row.ItemArray, separator);
        }

        public static String combine(DataRow row, String[] rowColumns, String separator) {
            Object[] items = new Object[rowColumns.Length];
            for(int i = 0; i < rowColumns.Length; i++){
                items[i] = row[rowColumns[i]];
            }
            return TextHelper.combine(items, separator);
        }
        
        public static String combine<T>(List<T> list) {
            return TextHelper.combine<T>(list.ToArray());
        }
        public static String combine<T>(List<T> list, String separator) {
            return TextHelper.combine<T>(list.ToArray(), separator);
        }
        public static String combine<T>(List<T> list, String formatString, String separator) {
            return TextHelper.combine<T>(list.ToArray(), formatString, separator);
        }


        public static String combine<T>(T[] array) {
            return TextHelper.combine<T>(array,null);
        }
        public static String combine<T>(T[] array, String separator) {
            return TextHelper.combine<T>(array, "{0}", separator);
        }



        public static String combine<T>(T[] array, String formatString
                                    , String separator) {
            List<String> list = new List<string>();
           
            if(formatString == null) formatString = "{0}";
            for(int i = 0; i < array.Length; i++) {
                Object o = (Object)array[i];
                if(o != null && o != DBNull.Value) {
                    String s = String.Format(formatString, o).Trim();
                    if(s != String.Empty) {
                        list.Add(s);
                    }
                }
                
            }
            StringBuilder SB = new StringBuilder();
            for(int i = 0; i < list.Count; i++) {
                if(i < list.Count-1) {
                    SB.Append(list[i]+separator);
                } else {
                    SB.Append(list[i]);
                }
            }

            return SB.ToString();
        }



        public static String combine<T>(IList<T> values, String separator, int valuesPerLine){
            return TextHelper.combine<T>(values.ToArray(), separator, valuesPerLine);
        }
        public static String combine<T>(T[] values, String separator, int valuesPerLine) {
            return TextHelper.combine<T>(values, "{0}", separator, valuesPerLine);
        }
        public static String combine<T>(T[] values, String formatString, String separator, int valuesPerLine) {
            int columnsInRow = 0;
            StringBuilder SB = new StringBuilder();
            String formatSep = formatString+separator;
            for(int i=0; i < values.Length; i++) {
                if(i < values.Length -1) {
                    SB.AppendFormat(formatSep, values[i]);
                } else {
                    SB.AppendFormat(formatString, values[i]);
                }
                columnsInRow++;
                if(columnsInRow >= valuesPerLine) {
                    SB.AppendLine(String.Empty);
                    columnsInRow = 0;
                }
            }

            return SB.ToString();
        }


        /// <summary>
        /// Takes an Exception and returns a formatted String showin the Source, Message and the StackTrace Informations.
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static String Exception2String(Exception ex) {
            return String.Format("Source: {0} \nMessage: {1} \nStackTrace:\n{2}", ex.Source, ex.Message, ex.StackTrace);
        
        }
    }
}
